// Alpha1.java - Alexander Shabarshin  28.10.2008
// version 1.5 ( see http://3niti.org )

// 14.11.2008 (v1.5) - fixed register A and data display
// 12.11.2008 (v1.4) - fixed register A display
// 11.11.2008 (v1.3) - big endian LDI and JMP
// 07.11.2008 (v1.2) - correctly implemented flag RSF
// 06.11.2008 (v1.1) - fixed saving of zero address in case of interrupt
// 05.11.2008 (v1.0) - initial version (writing to ROM is allowed)

import java.applet.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

public class Alpha1 extends Applet implements Runnable, MouseListener
{
 Thread thread = null;
 int[] leds;
 int[] swis;
 int[] swix;
 int gStep,PC;
 int rsf,dpf,bcf;
 Ternary A;
 Ternary B;
 Ternary[] ram;
 Ternary[] rom;
 int[] D;
 public static final int MEM_SZ = 2187;
 public static final int MEM_MX = 1094;

 public void init()
 {
   setBackground(new Color(255,255,255));
   leds = new int[15];
   swis = new int[15];
   swix = new int[15];
   rom = new Ternary[MEM_SZ];
   ram = new Ternary[MEM_SZ];
   for(int i=0;i<MEM_SZ;i++)
   {
     rom[i] = new Ternary(0);
     ram[i] = new Ternary(0);
   }
   A = new Ternary(0);
   B = new Ternary(0);
   D = new int[3];
   addMouseListener(this);
 }
   
 public void paint(Graphics g)
 {
   int i,x,y,k,w;
   int dx = size().width;
   int dy = size().height;
   int st = dx/18;
   gStep = st;
   x = st/2;
   for(i=0;i<15;i++)
   {
       y = st/2;
       switch(leds[i])
       {
         case -1: g.setColor(new Color(0xFF,0x00,0x00)); break;
         case  0: g.setColor(new Color(0xFF,0xFF,0xFF)); break;
         case  1: g.setColor(new Color(0x00,0xFF,0x00)); break;
       }   
       g.fillOval(x,y,st,st);
       g.setColor(new Color(0,0,0));
       g.drawOval(x,y,st,st);
       y += st + st/2;
       k = x + st/4;
       w = st/2;
       g.setColor(new Color(255,255,255));    
       g.fillRect(k,y,w,st);
       y--;
       g.setColor(new Color(0,0,0));
       g.drawRect(k,y,w,st);
       y++;
       switch(swis[i])
       {
         case -1: g.fillRect(k,y+2*st/3,w,st/3); break;
         case  0: g.fillRect(k,y+st/3,w,st/3); break;
         case  1: g.fillRect(k,y,w,st/3); break;
       }
       swix[i] = k;
       x += st;
       if((i%3)==2) x+= st/2;
   }
 }

 public void update(Graphics g)
 {
   paint(g);
 }

 public void run()
 {
   boolean fstep = false;
   boolean fsave = false;
   int SP = 0;
   while(true)
   {
/*
        int i = (int)(Math.random()*15);
        if(Math.random() > 0.5) 
        {
           leds[i]++;
           if(leds[i]==2) leds[i] = -1;
        }
        else 
        {
           leds[i]--;
           if(leds[i]==-2) leds[i] = 1;
        }
*/
        String s = "";
        Ternary t = new Ternary(swis[11],swis[10],swis[9]);
        int aa = 0;
        int k = 1;
        for(int j=8;j>=0;j--)
        {
          aa += swis[j]*k;
          k *= 3;
        }
        switch(swis[12])
        {
           case -1: s=get(aa).toString(); break;
           case  0: s=get(PC).toString(); break;
           case  1: set(aa,t);s=t.toString(); break;
        }
        k = s.length();
        for(int i=0;i<3;i++)
        {
           if(i < 3-k) leds[9+i] = 0;
           else
           {
              switch(s.charAt(i-3+k))
              {
                case 'N': leds[9+i] = -1; break;
                case 'O': leds[9+i] =  0; break;
                case 'P': leds[9+i] =  1; break;
              }
           }
        }
        t = new Ternary(PC);
        System.out.println("PC="+PC+" ("+t+")");
        s = t.toString();
        k = s.length();
        for(int j=0;j<9;j++)
        {
           if(j < 9-k) leds[j] = 0;
           else
           {
              switch(s.charAt(j-9+k))
              {
                case 'N': leds[j] = -1; break;
                case 'O': leds[j] =  0; break;
                case 'P': leds[j] =  1; break;
              }
           }
        }
        switch(swis[13])
        {
           case -1: if(fsave){
                    fsave=false;
                    PC=SP;
                    SP=0;
                    } 
                    break;
           case  1: if(!fsave){
                    fsave=true;   
                    SP=PC;
                    PC=aa;
                    }
                    break;
        }
        switch(swis[14])
        {
           case -1: step(); 
                    break;
           case  0: fstep=false; 
                    break;
           case  1: if(!fstep){
                    step();
                    fstep=true;};
                    break;
        }
        s = A.toString();
        k = s.length();
        for(int i=0;i<3;i++)
        {
           if(i < 3-k) leds[12+i] = 0;
           else
           {
              switch(s.charAt(i-3+k))
              {
                case 'N': leds[12+i] = -1; break;
                case 'O': leds[12+i] =  0; break;
                case 'P': leds[12+i] =  1; break;
              }
           }
        }
      try {
        repaint();
        thread.sleep(250);
      } catch(Exception e) {
        System.out.println("Exception "+e);
      }   
   }
 }

 public void start()
 {
   if(thread==null)
   {
      thread = new Thread(this);
      thread.start();
   }
 }

 public void stop()
 {
   if(thread!=null)
   {
      thread.stop();
      thread = null;
   }
 }

 public void mousePressed(MouseEvent e)
 {
 }

 public void mouseReleased(MouseEvent e)
 {
 }

 public void mouseEntered(MouseEvent e)
 {
 }

 public void mouseExited(MouseEvent e)
 {
 }

 public void mouseClicked(MouseEvent e)
 {
   int i;
   int x = e.getX();
   int y = e.getY();
   int st2 = gStep/2;
   int y0 = gStep*2;
   int y1 = y0+st2;
   int y2 = y0+gStep;
   if(y > y0 && y < y1)
   {
     for(i=0;i<15;i++)
     {
       if(x > swix[i] && x < swix[i]+st2)
       {
          if(swis[i] < 1) swis[i]++;
          break;
       }
     }
   }
   if(y > y1 && y < y2)
   {
     for(i=0;i<15;i++)
     {
       if(x > swix[i] && x < swix[i]+st2)
       {
          if(swis[i] > -1) swis[i]--;
          break;
       }
     }
   }
 }

 Ternary get(int a)
 {
   Ternary t;
   if(a >= MEM_MX && a < MEM_MX+MEM_SZ)
   {
      t = ram[a-MEM_MX];
   }
   else if(a > -MEM_MX && a < MEM_MX)
   {
      t = rom[a+MEM_MX-1];
   }
   else 
   {
      t = new Ternary(0);
   }
   System.out.println("get "+a+" -> "+t);
   return t;
 }

 void set(int a, Ternary t)
 {
   System.out.println("set "+a+" <- "+t);

   if(a > -MEM_MX && a < MEM_MX)
   {
      rom[a+MEM_MX-1] = new Ternary(t);
   }

   if(a >= MEM_MX && a < MEM_MX+MEM_SZ)
   {
      ram[a-MEM_MX] = new Ternary(t);
   }
 }

 Ternary getA()
 {
   return A;
 }

 void setA(Ternary t)
 {
   A = t;
 }

 Ternary getB()
 {
   return B;
 }

 void setB(Ternary t)
 {
   B = t;
 }

 Ternary getF()
 {
   return new Ternary(rsf*9+dpf*3+bcf);
 }

 void setF(Ternary t)
 {
   String s = t.toString();
   int ibcf = s.length() - 1;
   int idpf = ibcf - 1;
   int irsf = idpf - 1;
   if(irsf < 0) rsf = 0;
   else
   {
     switch(s.charAt(irsf))
     {
       case 'N': rsf = -1; break;
       case 'O': rsf =  0; break;
       case 'P': rsf =  1; break;
     }
   }
   if(idpf < 0) dpf = 0;
   else
   {
     switch(s.charAt(idpf))
     {
       case 'N': dpf = -1; break;
       case 'O': dpf =  0; break;
       case 'P': dpf =  1; break;
     }
   }
   switch(s.charAt(ibcf))
   {
     case 'N': bcf = -1; break;
     case 'O': bcf =  0; break;
     case 'P': bcf =  1; break;
   }
 }

 int getDi()
 {
   return D[dpf+1];
 }

 Ternary getD()
 {
   return new Ternary(getDi());
 }

 void setD(Ternary t)
 {
   D[dpf+1] = t.get();
 }

 void setD(int i)
 {
   D[dpf+1] = i;
 }

 void setD(int h, int m, int l)
 {
   setD(new Ternary(27*(27*h+m)+l));
 }

 Ternary getTriade(String s, int ll)
 {
   int il = ll - 1;
   int im = il - 1;
   int ih = im - 1;
   int i = 0;
   if(ih>=0)
   {
     if(s.charAt(ih)=='P') i+=9;
     if(s.charAt(ih)=='N') i-=9;
   }
   if(im>=0)
   {
     if(s.charAt(im)=='P') i+=3;
     if(s.charAt(im)=='N') i-=3;
   }
   if(il>=0)
   {
     if(s.charAt(il)=='P') i+=1;
     if(s.charAt(il)=='N') i-=1;
   }
   return new Ternary(i);
 }

 Ternary getL()
 {
   String s = getD().toString();
   return getTriade(s,s.length());
 }
                                  
 Ternary getM()
 {
   String s = getD().toString();
   return getTriade(s,s.length()-3);
 }

 Ternary getH()
 {
   String s = getD().toString();
   return getTriade(s,s.length()-6);
 }

 void setL(Ternary t)
 {
   setD(getH().get(),getM().get(),t.get());
 }

 void setM(Ternary t)
 {
   setD(getH().get(),t.get(),getL().get());
 }
         
 void setH(Ternary t)
 {
   setD(t.get(),getM().get(),getL().get());
 }

 Ternary getN()
 {
   return get(D[0]);
 }

 void setN(Ternary t)
 {
   set(D[0],t);
 }

 Ternary getO()
 {
   return get(D[1]);
 }

 void setO(Ternary t)
 {
   set(D[1],t);
 }

 Ternary getP()
 {
   return get(D[2]);
 }

 void setP(Ternary t)
 {
   set(D[2],t);
 }

 void opa(Ternary f)
 {
   String s = f.toString();
   int il = s.length() - 1;
   int im = il - 1;
   int ih = im - 1;
   int i = 0;
   int j = 0;
   int k = 0;
   if(ih>=0)
   {
     if(s.charAt(ih)=='P') i =  1;
     if(s.charAt(ih)=='N') i = -1;
   }
   if(im>=0)
   {
     if(s.charAt(im)=='P') j =  1;
     if(s.charAt(im)=='N') j = -1;
   }
   if(il>=0)
   {
     if(s.charAt(il)=='P') k =  1;
     if(s.charAt(il)=='N') k = -1;
   }
   s = A.toString();
   il = s.length() - 1;
   im = il - 1;
   ih = im - 1;
   int r = 0;
   if(ih>=0)
   {
     switch(s.charAt(ih))
     {
       case 'N': r+=9*i; break;
       case 'O': r+=9*j; break;
       case 'P': r+=9*k; break;
     }
   }
   if(im>=0)
   {
     switch(s.charAt(im))
     {
       case 'N': r+=3*i; break;
       case 'O': r+=3*j; break;
       case 'P': r+=3*k; break;
     }
   }
   if(il>=0)
   {
     switch(s.charAt(il))
     {
       case 'N': r+=i; break;
       case 'O': r+=j; break;
       case 'P': r+=k; break;
     }
   }
   A = new Ternary(r);
 }

 void opb(Ternary fn, Ternary fo, Ternary fp)
 {
   String s = fn.toString();
   int il = s.length() - 1;
   int im = il - 1;
   int ih = im - 1;
   int in = 0;
   int jn = 0;
   int kn = 0;
   if(ih>=0)
   {
     if(s.charAt(ih)=='P') in =  1;
     if(s.charAt(ih)=='N') in = -1;
   }
   if(im>=0)
   {
     if(s.charAt(im)=='P') jn =  1;
     if(s.charAt(im)=='N') jn = -1;
   }
   if(il>=0)
   {
     if(s.charAt(il)=='P') kn =  1;
     if(s.charAt(il)=='N') kn = -1;
   }
   s = fo.toString();
   il = s.length() - 1;
   im = il - 1;
   ih = im - 1;
   int io = 0;
   int jo = 0;
   int ko = 0;
   if(ih>=0)
   {
     if(s.charAt(ih)=='P') io =  1;
     if(s.charAt(ih)=='N') io = -1;
   }
   if(im>=0)
   {
     if(s.charAt(im)=='P') jo =  1;
     if(s.charAt(im)=='N') jo = -1;
   }
   if(il>=0)
   {
     if(s.charAt(il)=='P') ko =  1;
     if(s.charAt(il)=='N') ko = -1;
   }
   s = fp.toString();
   il = s.length() - 1;
   im = il - 1;
   ih = im - 1;
   int ip = 0;
   int jp = 0;
   int kp = 0;
   if(ih>=0)
   {
     if(s.charAt(ih)=='P') ip =  1;
     if(s.charAt(ih)=='N') ip = -1;
   }
   if(im>=0)
   {
     if(s.charAt(im)=='P') jp =  1;
     if(s.charAt(im)=='N') jp = -1;
   }
   if(il>=0)
   {
     if(s.charAt(il)=='P') kp =  1;
     if(s.charAt(il)=='N') kp = -1;
   }
   String sb = B.toString();
   int bl = sb.length() - 1;
   int bm = bl - 1;
   int bh = bm - 1;
   int ib = 0;
   int jb = 0;
   int kb = 0;
   if(bh>=0)
   {
     if(s.charAt(bh)=='P') ib =  1;
     if(s.charAt(bh)=='N') ib = -1;
   }
   if(bm>=0)
   {
     if(s.charAt(bm)=='P') jb =  1;
     if(s.charAt(bm)=='N') jb = -1;
   }
   if(bl>=0)
   {
     if(s.charAt(bl)=='P') kb =  1;
     if(s.charAt(bl)=='N') kb = -1;
   }
   s = A.toString();
   il = s.length() - 1;
   im = il - 1;
   ih = im - 1;
   int r = 0;
   if(ih>=0)
   {
     switch(s.charAt(ih))
     {
       case 'N': 
         switch(ib)
         {
           case -1: r+=9*in; break;
           case  0: r+=9*io; break;
           case  1: r+=9*ip; break;
         }
         break;
       case 'O':
         switch(ib)
         {
           case -1: r+=9*jn; break;
           case  0: r+=9*jo; break;
           case  1: r+=9*jp; break;
         }
         break;
       case 'P':
         switch(ib)
         {
           case -1: r+=9*kn; break;
           case  0: r+=9*ko; break;
           case  1: r+=9*kp; break;
         }
         break;
     }
   }
   if(im>=0)
   {
     switch(s.charAt(im))
     {
       case 'N': 
         switch(jb)
         {
           case -1: r+=3*in; break;
           case  0: r+=3*io; break;
           case  1: r+=3*ip; break;
         }
         break;
       case 'O':
         switch(jb)
         {
           case -1: r+=3*jn; break;
           case  0: r+=3*jo; break;
           case  1: r+=3*jp; break;
         }
         break;
       case 'P':
         switch(jb)
         {
           case -1: r+=3*kn; break;
           case  0: r+=3*ko; break;
           case  1: r+=3*kp; break;
         }
         break;
     }
   }
   if(il>=0)
   {
     switch(s.charAt(il))
     {
       case 'N': 
         switch(kb)
         {
           case -1: r+=in; break;
           case  0: r+=io; break;
           case  1: r+=ip; break;
         }
         break;
       case 'O':
         switch(kb)
         {
           case -1: r+=jn; break;
           case  0: r+=jo; break;
           case  1: r+=jp; break;
         }
         break;
       case 'P':
         switch(kb)
         {
           case -1: r+=kn; break;
           case  0: r+=ko; break;
           case  1: r+=kp; break;
         }
         break;
     }
   }
   A = new Ternary(r);

 } 

 void signA()
 {
   int ai = A.get();
   if(ai  > 0) rsf =  1;
   if(ai == 0) rsf =  0;
   if(ai  < 0) rsf = -1;
 }

 int step()
 {
   int i,j,k,st=1;
   String s;
   Ternary tt, t = get(PC++);
   switch(t.get())
   {
     case Ternary.NNN: setN(A); break; // SAN
     case Ternary.NNO: setO(A); break; // SAO
     case Ternary.NNP: setP(A); break; // SAP
     case Ternary.NON: setF(A); break; // SAF
     case Ternary.NOO: setD(PC); break; // SPCD
     case Ternary.NOP: setB(A); break; // SAB
     case Ternary.NPN: setL(A); break; // SAL
     case Ternary.NPO: setM(A); break; // SAM
     case Ternary.NPP: setH(A); break; // SAH

     case Ternary.ONN: // RLA
       tt = new Ternary(A.get()*3+bcf);
       s = tt.toString();
       i = s.length()-3;
       if(i<0) bcf = 0;
       else
       {
         switch(s.charAt(i))
         {
           case 'N': bcf = -1; break;
           case 'O': bcf =  0; break;
           case 'P': bcf =  1; break;
         }
       }
       A = getTriade(s,i+3);
       break;

     case Ternary.ONO: // ADD
       tt = new Ternary(A.get()+B.get()+bcf);
       s = tt.toString();
       i = s.length()-3;
       if(i<0) bcf = 0;
       else
       {
         switch(s.charAt(i))
         {
           case 'N': bcf = -1; break;
           case 'O': bcf =  0; break;
           case 'P': bcf =  1; break;
         }
       }
       A = getTriade(s,i+3);
       signA();
       break;

     case Ternary.ONP: // RRA
       j = 0;
       s = A.toString();
       switch(s.charAt(s.length()-1))
       {
         case 'N': j = -1; break;
         case 'O': j =  0; break;
         case 'P': j =  1; break;
       }
       A = new Ternary(A.get()/3+bcf*9);
       bcf = j;
       break;

     case Ternary.OON: // LAI #
       A = get(PC++);
       st++;
       break;

     case Ternary.OOO: // ADI #
       tt = get(PC++);
       tt = new Ternary(A.get()+tt.get()+bcf);
       s = tt.toString();
       i = s.length()-3;
       if(i<0) bcf = 0;
       else
       {
         switch(s.charAt(i))
         {
           case 'N': bcf = -1; break;
           case 'O': bcf =  0; break;
           case 'P': bcf =  1; break;
         }
       }
       A = getTriade(s,i+3);
       signA();
       st++;
       break;

     case Ternary.OOP: // OPA #
       opa(get(PC++));
       signA();
       st++;
       break;

     case Ternary.OPN: // LDI # # #
       i = get(PC++).get();
       j = get(PC++).get();
       k = get(PC++).get();
       setD(i,j,k);
       st+=3;
       break;

     case Ternary.OPO: // JMP # # #
       i = get(PC++).get();
       j = get(PC++).get();
       k = get(PC++).get();
       PC = 27*(27*i+j)+k;
       st+=3;
       break;

     case Ternary.OPP: // OPB # # #
       Ternary tn = get(PC++);
       Ternary to = get(PC++);
       Ternary tp = get(PC++);
       opb(tn,to,tp);
       signA();
       st+=3;
       break;

     case Ternary.PNN: A=getN(); break; // LAN
     case Ternary.PNO: A=getO(); break; // LAO
     case Ternary.PNP: A=getP(); break; // LAP
     case Ternary.PON: A=getF(); break; // LAF
     case Ternary.POO: PC=getDi(); break; // LPCD
     case Ternary.POP: A=getB(); break; // LAB
     case Ternary.PPN: A=getL(); break; // LAL
     case Ternary.PPO: A=getM(); break; // LAM
     case Ternary.PPP: A=getH(); break; // LAH
   }
   System.out.println("step "+t);
   return st;
 }

} 
